﻿using System;

namespace Grimgine.Math
{
    /// <summary>
    /// A math helper class that contains math constants and useful functions
    /// </summary>
    public class MathHelper
    {
        #region Math Constants

        /// <summary>
        /// Represents the value of Pi (180 degrees)
        /// </summary>
        public const float Pi      = 3.1415926535897932384626433832795f;
       
        /// <summary>
        /// Represents Pi / 2 (90 degrees)
        /// </summary>
        public const float HalfPi  = 1.5707963267948966192313216916398f;
        
        /// <summary>
        /// Represents 2Pi (360 degrees)
        /// </summary>
        public const float TwoPi   = 2.0f * Pi;

        /// <summary>
        /// Represents a value "close to zero", the smallest float value possible.
        /// </summary>
        public const float Epsilon = float.Epsilon;

        #endregion

        #region Useful Math Functions

        /// <summary>
        /// 
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static float Sin(float angle)
        {
            return (float)System.Math.Sin((double)angle);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static double Sin(double angle)
        {
            return System.Math.Sin(angle);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static float Cos(float angle)
        {
            return (float)System.Math.Cos((double)angle);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="angle"></param>
        /// <returns></returns>
        public static double Cos(double angle)
        {
            return System.Math.Cos(angle);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static float Sqrt(float value)
        {
            return (float)System.Math.Sqrt((double)value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static double Sqrt(double value)
        {
            return System.Math.Sqrt(value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static float InvSqrt(float value)
        {
            return 1f / (float)System.Math.Sqrt(value);
        }

        /// <summary>
        /// Clamps an integer to the byte range [0, 255]
        /// </summary>
        /// <param name="value">Integer value to be clamped</param>
        /// <returns>The clamped value</returns>
        public static byte ClampToByte(int value)
        {
            if (value < byte.MinValue)
                return 0;
            else if (value > byte.MaxValue)
                return byte.MaxValue;
            else
                return (byte)value;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public static double ClampAndRound(float value, float min, float max)
        {
            if (float.IsNaN(value))
                return 0.0;

            if (value < min)
                return (double)min;

            if (value > max)
                return (double) max;

            return System.Math.Round((double)value);
        }

        #endregion
    }
}
